/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/cal.c
 # RCS:         "@(#)$Revision: 1.16 $ $Date: 94/03/21 10:26:28 $"
 # Description: User routines for doing calibration of E1430 module
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#include "machType.h"

#    include <stdio.h>
#    include <string.h>
#    include <math.h>
#    ifndef DOS_OS
#      include <unistd.h>
#    endif
#    include <sys/termio.h>

#include "trice.h"
#include "err1430.h"

#ifndef lint
const char cal_fileId[] = "$Header: cal.c,v 1.16 94/03/21 10:26:28 chriss Exp $";
#endif

#define KEYBOARD	0
#define CONSOLE		1
#define CAL_BLOCKSIZE	1024
#define AMPL_REF_FREQ	12000.0
#define DECI_LEVEL	13
#define MAX_TABLE_SUM	200.0

/*****************************************************************************
 *
 * Setup of terminal for no echo and if running in Godzilla, turn off the
 * command interpretter.
 *
 ****************************************************************************/
static SHORTSIZ16 funky_term_stuff_on(void) 
{
  LONGSIZ32 flag, error;
  struct termio term;


  error = ioctl(CONSOLE, TCGETA, &term);	/* get current termio struct */
  if(error) {
    return(i1430_Error(ERR1430_IOCTL_ERROR, "getting termio structure", NULL));
  }

  term.c_lflag = ECHOE;		/* turn off echo */
  term.c_cc[VMIN] =1;		/* reads will do one character min */

  error = ioctl(CONSOLE, TCSETA, &term);	/* set current termio struct */
  if(error) {
    return(i1430_Error(ERR1430_IOCTL_ERROR, "setting termio structure", NULL));
  }

  return(0);
}


/*****************************************************************************
 *
 * Restore terminal echo and if running in Godzilla, turn on the
 * command interpretter.
 *
 ****************************************************************************/
static SHORTSIZ16 funky_term_stuff_off(void) 
{
  LONGSIZ32 flag, error;
  struct termio term;


  error = ioctl(CONSOLE, TCGETA, &term);	/* get current termio struct */
  if(error) {
    return(i1430_Error(ERR1430_IOCTL_ERROR, "getting termio structure", NULL));
  }
 
  term.c_lflag = ECHO | ECHOE | ICANON;		/* turn on echo */
  term.c_cc[VMIN] = 0;

  error = ioctl(CONSOLE, TCSETA, &term);	/* set current termio struct */
  if(error) {
    return(i1430_Error(ERR1430_IOCTL_ERROR, "setting termio structure", NULL));
  }

  return(0);
}

/*****************************************************************************
 *
 * Check for key being pressed.  Return  if key pressed, 0 if no key.
 *
 ****************************************************************************/
static char key_pressed(void) 
{
  char ch;
  LONGSIZ32 numChars;

  (void)ioctl(KEYBOARD, FIONREAD, &numChars);

  if(numChars) {
    read(KEYBOARD, &ch, 1);
    return(ch);
  }
  
  return (0);
 
}


/*****************************************************************************
 *
 * Get 32 bit value from VME port and convert it to float.
 *
 ****************************************************************************/
static SHORTSIZ16 i1430_get_data_32_float(SHORTSIZ16 la, FLOATSIZ64 *value) 
{
  SHORTSIZ16 error;
  union tag {
    LONGSIZ32 int32;
    struct {
#ifdef INTEL_PROC
      SHORTSIZ16 lo;
      SHORTSIZ16 hi;
#else
      SHORTSIZ16 hi;
      SHORTSIZ16 lo;
#endif
    } int16;
  }val; 
    

  error = e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &val.int16.hi);
  if(error) return(error);

  error = e1430_read_register_card(la, E1430_HP_SEND_DATA_REG, &val.int16.lo);
  if(error) return(error);

  *value = (FLOATSIZ64)val.int32;

  return(0);
}


/*****************************************************************************
 *
 * Calibrate reference frequency.  Prompt user for the reference frequency
 * that is being used.  Zoom to that frequency.  Collect blocks of data, 
 * measuring the phase change across the block and prompting the user to
 * adjust the TRICE reference oscillator to minimize this phase change.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_cal_reference_freq(SHORTSIZ16 la, SHORTSIZ16 groupID,
						FLOATSIZ64 refFreq) 
{
  SHORTSIZ16 error, reg, i;
  FLOATSIZ64 freq, phase, phaseLast, phaseUnwrap, phaseDiff, phaseStart;
  FLOATSIZ64 real, imag;
  FLOATSIZ32 buf[2*CAL_BLOCKSIZE];
  SHORTSIZ16 adcOverload, adcError;
  LONGSIZ32 actualCnt;

  (void)printf("\n\n****************** INTERNAL TIME BASE ADJUST *********************\n\n");

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* analog setup: 1V range, input differential, anti-alias on */
  error = e1430_set_analog_input(groupID, 1.0, E1430_COUPLING_DC, 
	E1430_ANTIALIAS_ON, E1430_INPUT_HI_CONN, E1430_INPUT_LO_FLOAT);
  if(error) return(error);

  /* switch to uncalibrated ADC1-only mode */
  reg = ADC_CONTROL_CAL_MODE_1 | ADC_CONTROL_DIAG_ADC1_PASS1;
  error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
  if(error) return(error);

  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_COMPLEX,
	E1430_DATA_SIZE_32, E1430_BLOCK_MODE, CAL_BLOCKSIZE, 
	E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  (void)printf("Connect a high frequency sine source with frequency accuracy\n"
		"of 5 ppm in the 1 to 4Mhz range at approximatly .5 volts\n"
		"RMS to the Analog In connector.\n\n");

  while(1) {
    (void)printf("Enter the exact frequency of the source in MHz: ");

    (void)fflush(stdout);

    if(1 == scanf("%lf", &freq)) break;

    (void)printf("\n");
  }

  (void)printf("\n");

  freq *= 1000000.0;		/* turn MHz into Hz */

  error = funky_term_stuff_on();
  if(error) return(error);

  /* zoom to reference frequency entered by user */
  error = e1430_set_decimation_bandwidth(groupID, DECI_LEVEL, DECI_LEVEL);
  if(error) return(error);

  error = e1430_set_center_frequency(groupID, freq/refFreq);
  if(error) return(error);

  do {			/* hang in loop til signalled to leave */
    error = i1430_start_meas_and_wait(la);
    if(error) return(error);

    error = e1430_read_float32_data(la, buf, 8 * CAL_BLOCKSIZE, 
					&adcOverload, &adcError, &actualCnt);
    if(error) return(error);

    real = (FLOATSIZ64)buf[0];			/* first phase point */
    imag = (FLOATSIZ64)buf[1];
    if(real == 0.0 && imag == 0.0) {
      phaseStart = phaseLast = phaseUnwrap = 0.0;
    }else{
      phaseStart = phaseLast = phaseUnwrap = atan2(imag, real);
    }

    for(i=2; i < 2 * CAL_BLOCKSIZE; i+=2) {
      real = (FLOATSIZ64)buf[i];
      imag = (FLOATSIZ64)buf[i+1];
      if(real == 0.0 && imag == 0.0) {
	phase = 0.0;
      }else{
        phase = atan2(imag, real);
      }
      phaseDiff = phase - phaseLast;
      phaseUnwrap += phaseDiff;
      if(phaseDiff > PI)  phaseUnwrap -= 2*PI; 
      if(phaseDiff < -PI)  phaseUnwrap += 2*PI;
      phaseLast = phase;
    }

    (void)printf(" Turn the Internal Time Base Adjust for 0.0 result: % #8.6f     \r",
				phaseUnwrap - phaseStart);

  (void)fflush(stdout);

  }while(!key_pressed());

  (void)printf("\n");

  return(0);
}


/*****************************************************************************
 *
 * Calibrate ADC1 offset
 *
 ****************************************************************************/
SHORTSIZ16 e1430_cal_adc1_offset(SHORTSIZ16 la, SHORTSIZ16 groupID)
{
  SHORTSIZ16 error, reg;
  FLOATSIZ32 offset;
  SHORTSIZ16 adcError, adcOverload;
  LONGSIZ32 actualCnt;

  (void)printf("\n\n******************* ADC1 OFFSET CALIBRATION **********************\n\n");

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* analog setup: 1V range, input grounded, anti-alias on */
  error = e1430_set_analog_input(groupID, 1.0, E1430_COUPLING_DC, 
	E1430_ANTIALIAS_ON, E1430_INPUT_HI_GROUND, E1430_INPUT_LO_GROUND);
  if(error) return(error);

  /* switch to uncalibrated ADC1-only mode */
  reg = ADC_CONTROL_CAL_MODE_1 | ADC_CONTROL_DIAG_ADC1_PASS1;
  error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
  if(error) return(error);

  /* turn on zoom filter */
  error = e1430_set_decimation_bandwidth(groupID, 1, 1);
  if(error) return(error);

  error = e1430_set_center_frequency(groupID, 0.0);
  if(error) return(error);

  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_REAL,
	E1430_DATA_SIZE_32, E1430_BLOCK_MODE, CAL_BLOCKSIZE, 
	E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  do {			/* hang in loop til signalled to leave */
    error = i1430_start_meas_and_wait(la);
    if(error) return(error);

    error = e1430_read_float32_data(la, &offset, 4, 
				&adcOverload, &adcError, &actualCnt);
    if(error) return(error);

    (void)printf(" Turn ADC1 Offset Adjust for 0.0 result: % #8.6f          \r", offset);

  (void)fflush(stdout);

  }while(!key_pressed());

  (void)printf("\n");

  return(0);
}


/*****************************************************************************
 *
 * Calibrate ADC1 reference
 *
 ****************************************************************************/
SHORTSIZ16 e1430_cal_adc1_reference(SHORTSIZ16 la, SHORTSIZ16 groupID,
						FLOATSIZ64 refFreq) 
{
  SHORTSIZ16 i, error, reg;
  FLOATSIZ64  mag, mag2;
  FLOATSIZ32 data[2 * CAL_BLOCKSIZE];
  SHORTSIZ16 adcError, adcOverload; 
  LONGSIZ32 actualCnt, calBlocksize;
  LONGSIZ32 dataSize;

  (void)printf("\n\n****************** ADC1 REFERENCE CALIBRATION ********************\n\n");

  (void)printf("Connect a 0.5000 Vrms 12Khz sine wave with voltage amplitude\n"
		"accuracy of .005 dB to the Analog In connector\n\n");

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* analog setup: 1V range, input grounded, anti-alias on */
  error = e1430_set_analog_input(groupID, 1.0, E1430_COUPLING_DC, 
	E1430_ANTIALIAS_ON, E1430_INPUT_HI_CONN, E1430_INPUT_LO_FLOAT);
  if(error) return(error);

  /* switch to uncalibrated ADC1-only mode */
  reg = ADC_CONTROL_CAL_MODE_1 | ADC_CONTROL_DIAG_ADC1_PASS1;
  error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
  if(error) return(error);

  /* zoom phase and turn on zoom filter */
  error = e1430_set_decimation_bandwidth(groupID, DECI_LEVEL, DECI_LEVEL);
  if(error) return(error);

  error = e1430_set_center_frequency(groupID, AMPL_REF_FREQ/refFreq);
  if(error) return(error);

  calBlocksize = 64L;
  dataSize = 8L;		/* 8 bytes per sample */

  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_COMPLEX,
	E1430_DATA_SIZE_32, E1430_BLOCK_MODE, calBlocksize, 
	E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  do {			/* hang in loop til signalled to leave */
    error = i1430_start_meas_and_wait(la);
    if(error) return(error);

    error = e1430_read_float32_data(la, data, dataSize*calBlocksize, 
					&adcOverload, &adcError, &actualCnt);
    if(error) return(error);

    mag = 0.0;

    for(i=0; i < 2 * calBlocksize; i+=2) {
      mag2 = (FLOATSIZ64)(data[i] * data[i]) + 
				(FLOATSIZ64)(data[i+1] * data[i+1]);
      if(mag2 > 0.0) {
        mag += 10.0 * log10(mag2);
      }
    }

    mag /= (FLOATSIZ64)calBlocksize;

    mag += 10.0 * log10(8.0);

    (void)printf(" Turn ADC1 Reference Adjust for 0.0 result: % #8.6f         \r", mag);

    (void)fflush(stdout);

  }while(!key_pressed());

  (void)printf("\n");

  return(0);
}


/*****************************************************************************
 *
 * Calibrate sum node.  This procedure requires that the ADC1 gain and 
 * offset be calibated and that a .5V RMS 20kHz+/-2Hz sine wave be applied
 * to the input.  
 *
 ****************************************************************************/
SHORTSIZ16 e1430_cal_sum_node(SHORTSIZ16 la, SHORTSIZ16 groupID,
						FLOATSIZ64 refFreq)
{
  SHORTSIZ16 error, reg, numBits;
  FLOATSIZ64 data, gain, scale, sumerror; 
  SHORTSIZ16 i, j;
  FLOATSIZ64 dacrms[2], mag, mag2;
  FLOATSIZ32 buf[2*CAL_BLOCKSIZE];
  LONGSIZ32 ldata[2*CAL_BLOCKSIZE];
  LONGSIZ32 actualCnt;
  SHORTSIZ16 adcOverload, adcError;
  char errStr[80];
  LONGSIZ32 dataSize;
  LONGSIZ32 calBlocksize;

  (void)printf("\n\n********************* SUM NODE CALIBRATION ***********************\n\n");

  (void)printf(" Turn the DAC1, DAC2, DAC3 Reference and DC Offset adjustments to get values\n"
	" nearest zero.  Use DC Offset adjustment to get out of ADC_ERROR condition.\n"
	" Repeatedly adjust the others in this order: DAC3, DAC2, then DAC1\n");

  (void)printf(" DAC1 Ref       DAC2 Ref       DAC3 Ref      DC Offset\n\n");

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* analog setup: 1V range, input grounded, anti-alias on */
  error = e1430_set_analog_input(groupID, 1.0, E1430_COUPLING_DC, 
	  E1430_ANTIALIAS_ON, E1430_INPUT_HI_CONN, E1430_INPUT_LO_FLOAT);
  if(error) return(error);
 
  do {			/* hang in loop til signalled to leave */
    dataSize = 4L;		/* 4 bytes per sample */
  
    error = e1430_set_data_format(groupID, E1430_DATA_TYPE_REAL,
	E1430_DATA_SIZE_32, E1430_BLOCK_MODE, 16L, E1430_APPEND_STATUS_OFF);
    if(error) return(error);

    /* turn off decimation filter */
    error = e1430_set_decimation_bandwidth(groupID, 0, 0);
    if(error) return(error);
 
    /* reset DSP */  
    error = i1430_release_sync(la, MEAS_CONTROL_RESET_DSP_MODE);
    if(error) return(error);
  
    error = i1430_pull_sync(la, MEAS_CONTROL_RESET_DSP_MODE);
    if(error) return(error);

    error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
    if(error) return(error);

    if(fabs(dacrms[0]) > MAX_TABLE_SUM || fabs(dacrms[1]) > MAX_TABLE_SUM) {
      /* switch to normal ADC mode */
      reg = ADC_CONTROL_CAL_MODE_RESET | ADC_CONTROL_DIAG_NORMAL;
      error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
      if(error) return(error);
    }

    reg = ADC_CONTROL_CAL_MODE_NORMAL | ADC_CONTROL_DIAG_NORMAL;
    error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
    if(error) return(error);

    scale = 1.0 / (FLOATSIZ64)(1 << 22);

    /* get all DAC error bits */
    dacrms[0] = dacrms[1] = 0.0;

    for(j=0; j<2; j++) {	/* do DAC1 and DAC2  */
      switch(j) {
	case 0:			/* DAC1 */
	  numBits = 9;
	  reg = ADC_CONTROL_CAL_MODE_NORMAL | ADC_CONTROL_DIAG_DAC1_BIT0;
	  break;

	case 1:			/* DAC2 */
	  numBits = 10;
	  reg = ADC_CONTROL_CAL_MODE_NORMAL | ADC_CONTROL_DIAG_DAC2_BIT0;
	  break;
      }

      for(i=0; i<numBits; i++) {
        error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg++);
        if(error) return(error);

        error = i1430_start_meas_and_wait(la);
        if(error) return(error);

        error = i1430_get_data_32_float(la, &data);
        if(error) return(error);

        data *= scale;

        /* accumulate deviations with noise off */
	dacrms[j] += data * (FLOATSIZ64)(1 << i);   /* sum Ai * 2^i */	
      }

    }	/* for DAC1 and DAC2 */

    /* get gain error */
    reg = ADC_CONTROL_CAL_MODE_NORMAL | ADC_CONTROL_DIAG_GAIN_ERR;

    error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
    if(error) return(error);

    error = i1430_start_meas_and_wait(la);
    if(error) return(error);

    error = i1430_get_data_32_float(la, &data);
    if(error) return(error);

    gain = data / (FLOATSIZ64)(1 << 24);  /* scale in terms of LSB of ADC1 */

    /*  get ADC2 output */
    error = e1430_set_blocksize(groupID, CAL_BLOCKSIZE);
    if(error) return(error);

    reg = ADC_CONTROL_CAL_MODE_NORMAL| ADC_CONTROL_DIAG_ADC2_PASS2;

    error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
    if(error) return(error);

    error = i1430_start_meas_and_wait(la);
    if(error) return(error);

    error = e1430_read_raw_data(la, (SHORTSIZ16 *)ldata, 
	dataSize * CAL_BLOCKSIZE, &adcOverload, &adcError, &actualCnt);
    if(error) return(error);

    /* return ADC to normal full calibration */
    reg = ADC_CONTROL_CAL_MODE_NORMAL | ADC_CONTROL_DIAG_NORMAL;
    error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
    if(error) return(error);

    scale = 1.0 / (FLOATSIZ64)(1L << 22);

    sumerror = 0.0;

    for(i=0; i<CAL_BLOCKSIZE; i++) { 	/* sum of all data points */
      sumerror += scale * (FLOATSIZ64)ldata[i];
    }

    sumerror /= (FLOATSIZ64)CAL_BLOCKSIZE;	/* average */

    sumerror -= 0.25;			/* correct for dither bit */
   
    /* do adjustment for DAC3 */

    /* zero zoom phase and turn on zoom filter */
    error = e1430_set_decimation_bandwidth(groupID, DECI_LEVEL, DECI_LEVEL);
    if(error) return(error);
  
    error = e1430_set_center_frequency(groupID, AMPL_REF_FREQ/refFreq);
    if(error) return(error);
  
    calBlocksize = 64L;
    dataSize = 8L;		/* 8 bytes per sample */
  
    error = e1430_set_data_format(groupID, E1430_DATA_TYPE_COMPLEX,
	  E1430_DATA_SIZE_32, E1430_BLOCK_MODE, calBlocksize, 
	  E1430_APPEND_STATUS_OFF);
    if(error) return(error);
 
    e1430_pause(0.3); 

    error = i1430_start_meas_and_wait(la);
    if(error) return(error);

    error = e1430_read_float32_data(la, (FLOATSIZ32 *)buf, 
		dataSize*calBlocksize, &adcOverload, &adcError, &actualCnt);
    if(error) return(error);

    mag = 0.0;

    for(i=0; i < 2 * calBlocksize; i+=2) {
      mag2 = (FLOATSIZ64)(buf[i] * buf[i]) + (FLOATSIZ64)(buf[i+1] * buf[i+1]);
      if(mag2 > 0.0) {
        mag += 10.0 * log10(mag2);
      }
    }

    mag /= (FLOATSIZ64)calBlocksize;

    mag += 10.0 * log10(8.0);

    /* check for ADC error */
    error = e1430_get_status(la, &reg);
    if(error) return(error);

    if(reg & E1430_MEAS_STATUS_ADC_ERROR) {
      (void)strcpy(errStr, "ADC_ERROR     ");
    }else{
      (void)strcpy(errStr, "              ") ;
    }


/*  printf(" DAC1 Ref         DAC2 Ref         DAC3 Ref         DC Offset\n\n");*/
    
    (void)printf(" % #9.3f      % #8.2f      % #9.4f     % #7.3f    %s\r",
	dacrms[0], dacrms[1], mag, sumerror, errStr);

    (void)fflush(stdout);

  }while(!key_pressed());

  (void)printf("\n\n");

  (void)printf("The following information is given for diagnostics only.\n"
	"No adjustments necessary.\n\n");

  (void)printf("Gain:         % #8.6f\n", gain);

  return(0);
}


/*****************************************************************************
 *
 * Calibrate common mode
 *
 ****************************************************************************/
SHORTSIZ16 e1430_cal_common_mode(SHORTSIZ16 la, SHORTSIZ16 groupID,
						FLOATSIZ64 refFreq) 
{
  SHORTSIZ16 error, reg;
  volatile SHORTSIZ16 *addr;
  LONGSIZ32 i;
  FLOATSIZ64 mag2, scale;
  LONGSIZ32 blocksize;
  union tag {
    LONGSIZ32 int32;
    struct {
#ifdef INTEL_PROC
      SHORTSIZ16 lo;
      SHORTSIZ16 hi;
#else
      SHORTSIZ16 hi;
      SHORTSIZ16 lo;
#endif
    } int16;
  }val; 
  char buf[80];  
  

  (void)printf("\n\n********************** COMMON MODE BALANCE ***********************\n\n");

  error = e1430_reset_module(groupID);
  if(error) return(error);

  /* analog setup: 8V range, input grounded, anti-alias on */
  error = e1430_set_analog_input(groupID, 8.0, E1430_COUPLING_DC, 
	E1430_ANTIALIAS_ON, E1430_INPUT_HI_CONN, E1430_INPUT_LO_FLOAT);
  if(error) return(error);

  /* switch to normal mode */
  reg = ADC_CONTROL_CAL_MODE_NORMAL | ADC_CONTROL_DIAG_NORMAL;
  error = e1430_write_register_image(la, E1430_ADC_CONTROL_REG, reg);
  if(error) return(error);

  /* zero zoom phase and turn on zoom filter */
  error = e1430_set_decimation_bandwidth(groupID, 14, 14);
  if(error) return(error);

  error = e1430_set_center_frequency(groupID, 1000.0/refFreq);
  if(error) return(error);

  blocksize = 128;

  error = e1430_set_data_format(groupID, E1430_DATA_TYPE_COMPLEX,
	E1430_DATA_SIZE_32, E1430_BLOCK_MODE, blocksize, 
	E1430_APPEND_STATUS_OFF);
  if(error) return(error);

  (void)printf("Connect a 0.5000 Vrms 1.000 Khz sine wave generator such that the\n"
     "hot lead is connected to both the center and shell of the Analog In\n"
     "connector and the ground lead is connected to the shell of the\n"
     "Ext Clk TTL connector.\n\n");

  addr = e1430_get_register_address(la, E1430_HP_SEND_DATA_REG);

  (void)sprintf(buf, "la = %hd reading E1430_HP_SEND_DATA_REG", (LONGSIZ32)la);

  do {			/* hang in loop til signalled to leave */
    error = i1430_start_meas_and_wait(la);
    if(error) return(error);

    mag2 = 0.0;

    E1430_TRY

      for(i=0; i < 2*blocksize; i++) {
        val.int16.hi = iwpeek( addr);
        val.int16.lo = iwpeek( addr);
        mag2 += (FLOATSIZ64)val.int32 * (FLOATSIZ64)val.int32; 
      }
      E1430_CHECK_BERR

    E1430_RECOVER {
      error = i1430_Error(ERR1430_BUS_ERROR, buf, NULL);      
      return(error);
    }

    error = e1430_get_scale_la(la, &scale);
    if(error) return(error);

    mag2 *= (scale * scale / (FLOATSIZ64)blocksize);

    (void)printf(" Adjust Common Mode Balance for lowest value: % #8.6f        \r", 
									mag2);

    (void)fflush(stdout);

  }while(!key_pressed());

  (void)printf("\n");

  return(0);

}


/*****************************************************************************
 *
 * Run all calibration routines
 *
 ****************************************************************************/
SHORTSIZ16 e1430_calibrate_all(SHORTSIZ16 la) 
{  

  SHORTSIZ16 error;
  SHORTSIZ16 groupID;
  FLOATSIZ64 refFreq;

  groupID = e1430_create_module_group(1, &la);
  if(groupID == 0) {
    return(i1430_Error(ERR1430_NO_GROUP, NULL, NULL));
  }

  error = e1430_get_sample_clock_freq_la(la, &refFreq);
  if(error) goto bailout;

  error = e1430_cal_reference_freq(la, groupID, refFreq);
  if(error) goto bailout;

  error = e1430_cal_adc1_reference(la, groupID, refFreq);
  if(error) goto bailout;

  error = e1430_cal_adc1_offset(la, groupID);
  if(error) goto bailout;

  error = e1430_cal_sum_node(la, groupID, refFreq);
  if(error) goto bailout;

  error = e1430_cal_common_mode(la, groupID, refFreq);
  if(error) goto bailout;

bailout:
  error = funky_term_stuff_off();
  if(error) return(error);

  error = e1430_delete_module_group(groupID);
  return(error);
}


